package server

import (
	"context"
	"encoding/json"
	"errors"
	jwt "github.com/golangblogs/gojwt"
	"github.com/google/uuid"
	"log"
	"month6/common/model/mysql"
	"month6/common/model/redis"
	"month6/common/proto/user"
	"month6/pkg"
	"strconv"
	"time"
)

func SuperLogin(req *user.SuperLoginReq) (*user.SuperLoginResp, error) {
	su := mysql.Super{}
	login, err := su.Login(req.Name, req.Password)
	if err != nil {
		return nil, errors.New("管理员身份验证失败")
	}

	token, err := jwt.NewJWT("month6").CreateToken(jwt.CustomClaims{ID: login.ID})
	if err != nil {
		return nil, errors.New("token生成失败")
	}

	return &user.SuperLoginResp{
		SuperId: int64(login.ID),
		Success: token,
	}, nil
}

func AddClass(req *user.AddClassReq) (*user.AddClassResp, error) {
	c := mysql.Class{
		UserId: int(req.UserId),
		Name:   req.Name,
		Price:  float64(req.Price),
		Cover:  req.Cover,
		Status: int(req.Status),
		Num:    int(req.Num),
	}
	err := c.AddClass()
	if err != nil {
		return nil, errors.New("课程发布失败")
	}
	return &user.AddClassResp{Success: "课程发布成功"}, nil
}

func ListClass(req *user.ListClassReq) (*user.ListClassResp, error) {
	c := mysql.Class{}
	list, err := c.List()
	if err != nil {
		return nil, errors.New("加载失败")
	}
	var lists []*user.ListClass
	for _, class := range list {
		lists = append(lists, &user.ListClass{
			Name:   class.Name,
			Price:  float32(class.Price),
			Cover:  class.Cover,
			Status: int64(class.Status),
			Num:    int64(class.Num),
		})
	}

	return &user.ListClassResp{List: lists}, nil
}

func DetailClass(req *user.DetailClassReq) (*user.DetailClassResp, error) {
	c := mysql.Class{}
	detail, err := c.Detail(req.Id)
	if err != nil {
		return nil, err
	}

	var list []*user.DetailClass
	for _, i := range detail {
		list = append(list, &user.DetailClass{
			Name:   i.Name,
			Price:  float32(i.Price),
			Cover:  i.Cover,
			Status: int64(i.Status),
			Num:    int64(i.Num),
		})
	}

	return &user.DetailClassResp{Detail: list}, nil
}

func UpdatedClassStatus(req *user.UpdatedClassStatusReq) (*user.UpdatedClassStatusResp, error) {
	c := mysql.Class{}
	err := c.UpdatedClassStatus(req.Id, req.Status)
	if err != nil {
		return nil, errors.New("课程状态操作失败")
	}
	return &user.UpdatedClassStatusResp{Success: "课程状态操作成功"}, nil
}

func AddRob(req *user.AddRobReq) (*user.AddRobResp, error) {
	c := mysql.Class{}
	find, err := c.Find(req.ClassId)
	if err != nil {
		return nil, err
	}

	c = mysql.Class{}
	list, err := c.List()
	if err != nil {
		return nil, errors.New("加载失败")
	}

	lockKey := "Rob:" + find.Name
	err = redis.RDB.SetNX(context.Background(), lockKey, find.Num, time.Minute*30).Err()
	if err != nil {
		return nil, errors.New("响应失败")
	}
	defer func() {
		err = redis.RDB.Del(context.Background(), lockKey).Err()
		if err != nil {
			log.Println("解锁失败")
		}
	}()

	rb := mysql.Rob{
		Name:     find.Name,
		Cover:    find.Cover,
		Price:    find.Price,
		NowPrice: float64(req.NowPrice),
	}
	err = rb.AddRob()

	key := "MiaoSha:" + find.Name
	for _, class := range list {
		marshal, err := json.Marshal(class)
		if err != nil {
			return nil, err
		}
		err = redis.RDB.LPush(context.Background(), key, marshal).Err()
		if err != nil {
			return nil, errors.New("商品预热失败")
		}
		redis.RDB.Expire(context.Background(), key, time.Minute*30)
	}

	if err != nil {
		return nil, errors.New("抢购课程发布失败")
	}
	return &user.AddRobResp{Success: "抢购课程发布成功"}, nil
}

func UserBuyClass(req *user.UserBuyClassReq) (*user.UserBuyClassResp, error) {
	xt := mysql.DB.Begin()

	c := mysql.Class{}
	find, err := c.Find(req.ClassId)
	if err != nil {
		xt.Rollback()
		return nil, err
	}

	lockKey := "Rob:" + req.Name
	err = redis.RDB.SetNX(context.Background(), lockKey, req.Num, time.Minute*30).Err()
	if err != nil {
		xt.Rollback()
		return nil, errors.New("响应失败")
	}
	defer func() {
		err = redis.RDB.Del(context.Background(), lockKey).Err()
		if err != nil {
			log.Println("解锁失败")
		}
	}()

	u := mysql.User{
		Name:      req.Name,
		ClassName: find.Name,
		Num:       int(req.Num),
	}

	if req.Num >= 2 {
		xt.Rollback()
		return nil, errors.New("每个用户只限购一份")
	}

	r := mysql.Rob{}
	rob, err := r.Find(req.RobId)
	if err != nil {
		return nil, err
	}
	format := time.Now().Format(time.DateTime)
	if rob.StartTime < format {
		return nil, errors.New("活动未开始，禁止抢购")
	}

	err = u.Buy()
	if err != nil {
		xt.Rollback()
		return nil, errors.New("失败")
	}

	nowNum := find.Num - int(req.Num)
	err = c.Updated(req.ClassId, nowNum)
	if err != nil {
		return nil, errors.New("库存扣减失败")
	}

	xt.Commit()
	return &user.UserBuyClassResp{Success: "用户购买成功"}, nil
}

func BrowseList(req *user.BrowseListReq) (*user.BrowseListResp, error) {
	b := mysql.Browse{}
	find, err := b.Find()
	if err != nil {
		return nil, err
	}

	var list []*user.BrowseList
	for _, i := range find {
		list = append(list, &user.BrowseList{
			LookNum:  int64(i.LookNum),
			BuyerNum: int64(i.BuyerNum),
			Money:    float32(i.Money),
		})
	}

	return &user.BrowseListResp{List: list}, nil
}

func BrowseList2(req *user.BrowseList2Req) (*user.BrowseList2Resp, error) {
	b := mysql.Browse{}
	find, err := b.Find()
	if err != nil {
		return nil, err
	}

	var list []*user.BrowseList2
	for _, i := range find {
		list = append(list, &user.BrowseList2{
			LookNum:   int64(i.LookNum),
			BuyerNum:  int64(i.BuyerNum),
			Money:     float32(i.Money),
			Name:      i.Name,
			ClassName: i.ClassName,
			Num:       int64(i.Num),
			Talk:      i.Talk,
		})
	}

	return &user.BrowseList2Resp{List2: list}, nil
}

func AddOrder(req *user.AddOrderReq) (*user.AddOrderResp, error) {
	c := mysql.Class{}
	find, err := c.Find(req.ClassId)
	if err != nil {
		return nil, err
	}

	Sn := uuid.New().String()
	o := mysql.Order{
		UserId:  int(req.UserId),
		ClassId: int(req.ClassId),
		OrderSn: Sn,
		Name:    find.Name,
		Price:   find.Price,
		Cover:   find.Cover,
		Num:     int(req.Num),
		PayType: int(req.PayType),
	}

	if req.Num > int64(find.Num) {
		return nil, errors.New("库存不够")
	}

	err = o.Created()
	if err != nil {
		return nil, errors.New("下单失败")
	}

	if o.Status == 1 {
		pkg.Cron(Sn)
	}

	amount := strconv.FormatFloat(find.Price, 'f', 2, 64)
	pay := pkg.NewAliPay()
	url := pay.Pay(find.Name, Sn, amount)
	return &user.AddOrderResp{Success: "下单成功" + url}, nil
}

func AliPay(req *user.AliPayReq) (*user.AliPayResp, error) {
	var status int
	if req.Status == "WAIT_BUYER_PAY" {
		status = 1
	} else if req.Status == "TRADE_CLOSED" {
		status = 2
	} else if req.Status == "TRADE_SUCCESS" {
		status = 3
	}

	o := mysql.Order{}
	err := o.FindUpdated(req.OrderSn, status)
	if err != nil {
		return nil, errors.New("回调失败")
	}
	return &user.AliPayResp{Success: "回调成功"}, nil
}
